<?php

namespace Henan\ThinkSdk\utils;

/**
 * GD图像工具
 */
class ImageUtil
{
    /**
     * 当前实例
     * @var ImageUtil
     */
    protected static ImageUtil $instance;

    /**
     * 字体
     * @var string
     */
    protected string $font = '';

    /**
     * 图片
     * @var
     */
    protected $image;

    /**
     * 等比例缩放
     */
    const SCALE = 'scale';

    /**
     * 裁剪
     */
    const CROP = 'crop';

    /**
     * 构造方法
     * @param  $bg
     * @param string $font
     */
    protected function __construct($bg, string $font)
    {
        $this->font = $font;
        if (is_string($bg)) {
            $img = imagecreatefromstring(file_get_contents($bg)); //从字符串的图像流中新建图像
            $width = imagesx($img);
            $height = imagesy($img);
            $thumb = imagecreatetruecolor($width, $height); //新建真彩色图像
            imagecopyresampled($thumb, $img, 0, 0, 0, 0, $width, $height, $width, $height); //重采样拷贝部分图像并调整大小
            imagecopymerge($img, $thumb, 0, 0, 0, 0, $width, $height, 100); //合并
            $this->image = $img;
        } else {
            $this->image = $bg;
        }
        return $this;
    }

    /**
     * 获取实例对象
     * @param  $bg
     * @param string $font
     * @return self
     */
    public static function instance($bg, string $font): self
    {
        if (is_null(self::$instance)) self::$instance = new static($bg, $font);
        return self::$instance;
    }

    /**
     * 添加图片
     * @param $file
     * @param int $x
     * @param int $y
     * @param int $w
     * @param int $h
     * @param string $model
     * @param int $radius
     * @param bool $isBase64
     * @return self
     */
    public function addImage($file, int $x = 0, int $y = 0, int $w = 0, int $h = 0, string $model = 'scale', int $radius = 0, bool $isBase64 = false): self
    {
        if (is_string($file)) {
            $content = $isBase64 ? base64_decode($file) : file_get_contents($file);
            $img = imagecreatefromstring($content); //从字符串的图像流中新建图像
        } else {
            $img = $file;
        }
        switch ($model) {
            case 'scale':
                $img = self::scaleImage($img, $w, $h);
                break;
            case 'crop':
                $img = self::cropImage($img, $w, $h);
                break;
            default:
                break;
        }
        $radius && $img = self::borderRadius($img, $radius);
        // imagecopy($this->image, $img,  $x, $y, 0, 0, imagesx($img), imagesy($img));
        imagecopymerge($this->image, $img, $x, $y, 0, 0, imagesx($img), imagesy($img), 100); //拷贝并合并图像的一部分
        return $this;
    }

    public function addPngImage($file, int $x = 0, int $y = 0, int $w = 0, int $h = 0)
    {
        $img = is_string($file) ? imagecreatefromstring(file_get_contents($file)) : $file;
        $png_width = imagesx($img);
        $png_height = imagesy($img);
// 创建一个透明色
        $transparent = imagecolorallocatealpha($this->image, 0, 0, 0, 127);
// 处理PNG图片的alpha通道
        for ($x = 0; $x < $png_width; $x++) {
            for ($y = 0; $y < $png_height; $y++) {
                $alpha = (imagecolorat($img, $x, $y) >> 24) & 0xFF;
                if ($alpha < 127) {
                    imagesetpixel($this->image, $x, $y, $transparent);
                } else {
                    imagecopy($this->image, $img, $x, $y, $x, $y, 1, 1);
                }
            }
        }
        return $this;
    }

    /**
     * 添加文本
     * @param $text
     * @param int $x
     * @param int $y
     * @param string $color
     * @param int $size
     * @param int $angle
     * @return $this
     */
    public function addText($text, int $x = 0, int $y = 0, string $color = '#1C2833', int $size = 24, int $angle = 0): self
    {

        [$r, $g, $b] = self::hexToRGB($color);
        $color = imagecolorallocate($this->image, $r, $g, $b); //为图像分配颜色
        imagettftext($this->image, $size, $angle, $x, $y, $color, $this->font, $text); // TrueType字体向图像写入文本
        return $this;
    }

    public function addLineText(string $text, int $y, string $color = '#1C2833', int $size = 24, string $align = 'center', int $angle = 0)
    {
        $fontBox = imagettfbbox($size, $angle, $this->font, $text);
        $x = ceil((imagesx($this->image) - $fontBox[2]) / 2);
        [$r, $g, $b] = self::hexToRGB($color);
        $color = imagecolorallocate($this->image, $r, $g, $b); //为图像分配颜色
        imagettftext($this->image, $size, $angle, $x, $y, $color, $this->font, $text); // TrueType字体向图像写入文本
        return $this;
    }

    /**
     * 添加水平渐变色蒙板
     * @param string $color
     * @param int $x1
     * @param int $y1
     * @param int $x2
     * @param int $y2
     * @param int $deep 渐变深度
     * @param bool $reverse 是否反转
     * @return $this
     */
    public function addHorizontalGradients(string $color, int $x1, int $y1, int $x2, int $y2, int $deep = 20, bool $reverse = false): self
    {
        [$r, $g, $b] = self::hexToRGB($color);
        $deep > 100 && $deep = 100;
        $deep <= 0 && $deep = 1;
        $h = abs($y2 - $y1);
        $step = round($h / $deep);
        $alphaStep = round((127 - 60) / $deep);
        for ($i = 0; $i < $deep; $i++) {
            $alpha = $reverse ? 60 + $i * $alphaStep : 127 - $i * $alphaStep;
            $color = imagecolorallocatealpha($this->image, $r, $g, $b, $alpha);
            imagefilledrectangle($this->image, $x1, ($y1 + $step * $i + 1), $x2, ($y1 + $step * ($i + 1)), $color);
        }
        return $this;
    }

    public static function loadImage($filename, $color = '#fff')
    {
        [$r, $g, $b] = self::hexToRGB($color);
        $content = file_get_contents($filename);
        $img = imagecreatefromstring($content); //从字符串的图像流中新建图像
        $x = imagesx($img);
        $y = imagesy($img);
        $newDes = imagecreatetruecolor($x, $y);
        $color = imagecolorallocate($newDes, $r, $g, $b);
        imagecolortransparent($newDes, $color);
        imagefill($newDes, 0, 0, $color);
        imagecopy($newDes, $img, 0, 0, 0, 0, $x, $y);
        return $newDes;
    }

    /**
     * 创建一张透明图片
     * @param $width
     * @param $height
     * @return false|\GdImage|resource
     */
    public static function createPngImage($width, $height)
    {
        $image = imagecreatetruecolor($width, $height);
        $transparent = imagecolorallocatealpha($image, 0, 0, 0, 127); //设置透明背景
        imagefill($image, 0, 0, $transparent);
        imagealphablending($image, true);
        imagesavealpha($image, true);
        return $image;
    }

    /**
     * 创建一张纯色图片
     * @param $w
     * @param $h
     * @param string $color
     * @return false|\GdImage|resource
     */
    public static function createImage($w, $h, string $color = '#fff')
    {
        [$r, $g, $b] = self::hexToRGB($color);
        $im = imagecreatetruecolor($w, $h);
        $color = imagecolorallocate($im, $r, $g, $b);
        imagefill($im, 0, 0, $color);
        return $im;
    }

    /**
     * 缩放图像
     * @param mixed $image GD图片资源
     * @param int $w 宽度（像素）
     * @param int $h 高度（像素）
     * @return false|GdImage|resource
     */
    public static function scaleImage($image, int $w = 0, int $h = 0)
    {
        [$width, $height] = [imagesx($image), imagesy($image)];
        $w == 0 && $h != 0 && $w = round($h * ($width / $height));
        $h == 0 && $w != 0 && $h = round($w * ($height / $width));
        $thumb = imagecreatetruecolor($w, $h); //新建真彩色图像
        imagecopyresampled($thumb, $image, 0, 0, 0, 0, $w, $h, $width, $height); //重采样拷贝部分图像并调整大小
        imagedestroy($image); //销毁图像
        return $thumb;
    }

    /**
     * 裁剪图像
     * @param mixed $image GD图片资源
     * @param int $w 宽度（像素）
     * @param int $h 高度（像素）
     * @return false|GdImage|resource
     */
    public static function cropImage($image, int $w, int $h)
    {
        [$width, $height] = [imagesx($image), imagesy($image)];
        $setRatio = $w / $h;
        $curRatio = $width / $height;
        if ($setRatio > $curRatio) {
            $resizeX = $width;
            $resizeY = $resizeX * $h / $w;
            $x = 0;
            $y = ($height - $resizeY) / 2;
        } elseif ($setRatio < $curRatio) {
            $resizeY = $height;
            $resizeX = $resizeY * $w / $h;
            $x = ($width - $resizeX) / 2;
            $y = 0;
        } else {
            $resizeX = $width;
            $resizeY = $height;
            $x = $y = 0;
        }
        $thumb = imagecreatetruecolor($w, $h); //新建真彩色图像
        imagecopyresampled($thumb, $image, 0, 0, $x, $y, $w, $h, $resizeX, $resizeY); //重采样拷贝部分图像并调整大小
        imagedestroy($image); //销毁图像
        return $thumb;
    }

    /**
     * 图片颜色替换
     * @param string $filename
     * @param string $oldColor
     * @param string $newColor
     * @return false|\GdImage|resource
     */
    public static function replaceColor1(string $filename, string $oldColor, string $newColor)
    {
        $content = file_get_contents($filename);
        $image = imagecreatefromstring($content);
        // $image = imagecreatefrompng($filename);
        [$r1, $g1, $b1] = self::hexToRGB($oldColor);
        [$r2, $g2, $b2] = self::hexToRGB($newColor);
        $color1 = imagecolorallocate($image, $r1, $r1, $r1);
        $color2 = imagecolorresolve($image, $r2, $g2, $b2);
        imagecolorallocate($image, $r2, $r2, $r2);
        var_dump($color1);
        $res = imagecolorset($image, $color1, $r2, $g2, $b2);
        var_dump($res);
        return $image;
    }

    /**
     * 图片颜色替换
     * @param string $filename
     * @param string $oldColor
     * @param string $newColor
     * @return false|\GdImage|resource
     */
    public static function replaceColor(string $filename, string $oldColor, string $newColor)
    {

        $content = file_get_contents($filename);
        $image = imagecreatefromstring($content);
        $newImage = imagecreatetruecolor(imagesx($image), imagesy($image));//创建画布
        imagesavealpha($newImage, true); //背景透明
        $background = imagecolorallocatealpha($newImage, 255, 255, 255, 127);
        imagefill($newImage, 0, 0, $background);//背景透明
        for ($y = 0; $y < imagesy($image); $y++) {
            for ($x = 0; $x < imagesx($image); $x++) {
                $rgb = imagecolorat($image, $x, $y);
                $rgba = imagecolorsforindex($image, $rgb);
                $s_colr = self::hex2rgb($oldColor);
                $r_colr = self::hex2rgb($newColor);
                if ($rgba['red'] == $s_colr['r'] && $rgba['green'] == $s_colr['g'] && $rgba['blue'] == $s_colr['b']) {
                    $rgba['red'] = $r_colr['r'];
                    $rgba['green'] = $r_colr['g'];
                    $rgba['blue'] = $r_colr['b'];
                } elseif ($rgba['red'] == 255 && $rgba['green'] == 255 && $rgba['blue'] == 255 && $rgba['alpha'] == 127) {
                } elseif ($rgba['red'] == 255 && $rgba['green'] == 255 && $rgba['blue'] == 255 && $rgba['alpha'] == 0) {
                } elseif ($rgba['alpha'] != 0) {
                } else {
                    //计算颜色
                    $rgba['red'] = $rgba['red'] + ((255 - $rgba['red']) * $r_colr['r'] / 255);//echo '【'.$s_colr['r'].'-'.$r_colr['r'].'-'.$rgba['red'].'】';
                    $rgba['green'] = $rgba['green'] + ((255 - $rgba['green']) * $r_colr['g'] / 255);
                    $rgba['blue'] = $rgba['blue'] + ((255 - $rgba['blue']) * $r_colr['b'] / 255);
                }
                $color = imagecolorallocatealpha($newImage, $rgba['red'], $rgba['green'], $rgba['blue'], $rgba['alpha']);
                imagesetpixel($newImage, $x, $y, $color);//一个像素放入画布
            }
        }
        return $newImage;
    }

    /**
     * RGB 转 十六进制
     * @param $rgb
     * @return string
     */
    public static function rgb2hex($rgb): string
    {
        $regexp = "/^rgb\(([0-9]{0,3})\,\s*([0-9]{0,3})\,\s*([0-9]{0,3})\)/";
        $re = preg_match($regexp, $rgb, $match);
        $re = array_shift($match);
        $hexColor = "#";
        $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
        for ($i = 0; $i < 3; $i++) {
            $r = null;
            $c = $match[$i];
            $hexAr = array();
            while ($c > 16) {

                $r = $c % 16;

                $c = ($c / 16) >> 0;

                array_push($hexAr, $hex[$r]);

            }
            array_push($hexAr, $hex[$c]);
            $ret = array_reverse($hexAr);
            $item = implode('', $ret);
            $item = str_pad($item, 2, '0', STR_PAD_LEFT);
            $hexColor .= $item;
        }
        return $hexColor;
    }

    /**
     * 十六进制 转 RGB
     * @param $hexColor
     * @return array
     */
    public static function hex2rgb($hexColor): array
    {
        $color = str_replace('#', '', $hexColor);
        if (strlen($color) > 3) {
            $rgb = [
                'r' => hexdec(substr($color, 0, 2)),
                'g' => hexdec(substr($color, 2, 2)),
                'b' => hexdec(substr($color, 4, 2))
            ];
        } else {
            $color = $hexColor;
            $r = substr($color, 0, 1) . substr($color, 0, 1);
            $g = substr($color, 1, 1) . substr($color, 1, 1);
            $b = substr($color, 2, 1) . substr($color, 2, 1);
            $rgb = ['r' => hexdec($r), 'g' => hexdec($g), 'b' => hexdec($b)];
        }
        return $rgb;
    }

    /**
     * 导出图片
     * @param $gdImage
     * @param string $filename
     * @return void
     */
    public static function output($gdImage, string $filename)
    {
        imagepng($gdImage, $filename);
        imagedestroy($gdImage); //释放资源
    }

    /**
     * 颜色hex值转换成rgb
     * @param string $hex
     * @return array
     */
    public static function hexToRGB(string $hex): array
    {
        if ($hex[0] == '#') $hex = substr($hex, 1);
        if (strlen($hex) == 6) {
            [$r, $g, $b] = [$hex[0] . $hex[1], $hex[2] . $hex[3], $hex[4] . $hex[5]];
        } elseif (strlen($hex) == 3) {
            [$r, $g, $b] = [$hex[0] . $hex[0], $hex[1] . $hex[1], $hex[2] . $hex[2]];
        } else {
            return [0, 0, 0];
        }
        $r = hexdec($r);
        $g = hexdec($g);
        $b = hexdec($b);
        return [$r, $g, $b];
    }

    /**
     * 保存为base64格式图片
     * @return string
     */
    public function writeBase64(): string
    {
        ob_start();
        imagepng($this->image);
        $string = ob_get_contents();
        ob_end_clean();
        return base64_encode($string);
    }

    /**
     * 保存图片到本地
     * @param $output
     * @return void
     */
    public function save($output)
    {
        imagepng($this->image, $output);  //保存PNG图片到本地
        imagedestroy($this->image); //释放内存
    }

    /**
     * 打开图片
     * @param string $filename 图片文件
     * @return false|\GdImage|resource
     */
    public static function open(string $filename)
    {
        $content = file_get_contents($filename); //获取图片内容
        return imagecreatefromstring($content); //从字符串的图像流中新建图像
    }

    /**
     * 真彩图片
     * @param $image
     * @return mixed
     */
    public static function trueColor($image)
    {
        $width = imagesx($image);
        $height = imagesy($image);
        $clip = imagecreatetruecolor($width, $height); //新建真彩色图像
        imagecopyresampled($clip, $image, 0, 0, 0, 0, $width, $height, $width, $height); //重采样拷贝部分图像并调整大小
        return $clip;
    }

    /**
     * 圆角图片
     * @param mixed $image GD图片资源
     * @param int $radius 圆角大小
     */
    public static function borderRadius($image, int $radius = 20)
    {
        $w = imagesx($image);
        $h = imagesy($image);
        $img = imagecreatetruecolor($w, $h);
        $color = imagecolorallocate($image, 255, 255, 255);
        imagecolortransparent($image, $color);
        imagesavealpha($img, true); // 设置透明通道
        $bg = imagecolorallocatealpha($img, 255, 255, 255, 127); // 拾取一个完全透明的颜色, 最后一个参数127为全透明
        imagefill($img, 0, 0, $bg);
        $r = $radius; // 圆 角半径
        for ($x = 0; $x < $w; $x++) {
            for ($y = 0; $y < $h; $y++) {
                $rgbColor = imagecolorat($image, $x, $y);
                if (($x >= $radius && $x <= ($w - $radius)) || ($y >= $radius && $y <= ($h - $radius))) {
                    imagesetpixel($img, $x, $y, $rgbColor); // 不在四角的范围内,直接画
                } else { // 在四角的范围内选择画
                    // 上左
                    $yx = $r; // 圆心X坐标
                    $yy = $r; // 圆心Y坐标
                    if (((($x - $yx) * ($x - $yx) + ($y - $yy) * ($y - $yy)) <= ($r * $r))) {
                        imagesetpixel($img, $x, $y, $rgbColor);
                    }
                    // 上右
                    $yx = $w - $r; // 圆心X坐标
                    $yy = $r; // 圆心Y坐标
                    if (((($x - $yx) * ($x - $yx) + ($y - $yy) * ($y - $yy)) <= ($r * $r))) {
                        imagesetpixel($img, $x, $y, $rgbColor);
                    }
                    // 下左
                    $yx = $r; // 圆心X坐标
                    $yy = $h - $r; // 圆心Y坐标
                    if (((($x - $yx) * ($x - $yx) + ($y - $yy) * ($y - $yy)) <= ($r * $r))) {
                        imagesetpixel($img, $x, $y, $rgbColor);
                    }
                    // 下右
                    $yx = $w - $r; // 圆心X坐标
                    $yy = $h - $r; // 圆心Y坐标
                    if (((($x - $yx) * ($x - $yx) + ($y - $yy) * ($y - $yy)) <= ($r * $r))) {
                        imagesetpixel($img, $x, $y, $rgbColor);
                    }
                }
            }
        }
        return $img;
    }

    /**
     * 导出图片
     * @param $image
     * @param string $filename 文件名称
     * @return void
     */
    public static function export($image, string $filename)
    {
        imagepng($image, $filename);  //保存PNG图片到本地
        imagedestroy($image); //释放内存
    }
}